package com.xiaoshuidi.cloud.module.contract.job;

import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itextpdf.text.Image;
import com.xiaoshuidi.cloud.framework.common.exception.ServiceException;
import com.xiaoshuidi.cloud.framework.common.pojo.CommonResult;
import com.xiaoshuidi.cloud.framework.filings.config.FilingsProperties;
import com.xiaoshuidi.cloud.framework.filings.core.FilingsApi;
import com.xiaoshuidi.cloud.framework.filings.core.enums.CodeTypeEnum;
import com.xiaoshuidi.cloud.framework.filings.core.enums.PaymentCycleEnum;
import com.xiaoshuidi.cloud.framework.filings.core.enums.UriEnum;
import com.xiaoshuidi.cloud.framework.filings.core.service.dto.CommonFilingsResponse;
import com.xiaoshuidi.cloud.framework.filings.core.service.dto.ContractSigningBo;
import com.xiaoshuidi.cloud.framework.filings.core.service.dto.ContractSigningResp;
import com.xiaoshuidi.cloud.framework.filings.core.service.dto.FilesUploadResp;
import com.xiaoshuidi.cloud.framework.filings.core.util.RSAUtil;
import com.xiaoshuidi.cloud.framework.tenant.core.aop.TenantIgnore;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.ContractRoomDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.contract.ElectronicContractDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.filings.ContractFilingsDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.filings.ContractFilingsLogDO;
import com.xiaoshuidi.cloud.module.contract.dal.dataobject.roommeta.ContractRoommateDO;
import com.xiaoshuidi.cloud.module.contract.dal.mysql.contract.ElectronicContractMapper;
import com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractFilingsEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractFilingsLogEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractStatusEnum;
import com.xiaoshuidi.cloud.module.contract.service.contract.ContractRoomService;
import com.xiaoshuidi.cloud.module.contract.service.filings.ContractFilingsLogService;
import com.xiaoshuidi.cloud.module.contract.service.filings.ContractFilingsService;
import com.xiaoshuidi.cloud.module.contract.service.roommate.ContractRoommateService;
import com.xiaoshuidi.cloud.module.contract.util.pdf.ImgToPdfUtil;
import com.xiaoshuidi.cloud.module.contract.util.pdf.PdfToImgUtil;
import com.xiaoshuidi.cloud.module.rooms.api.roomhouse.RoomHouseApi;
import com.xiaoshuidi.cloud.module.rooms.api.roomhouse.vo.RoomHouseFilingsResp;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants.CONTRACT_FILE_UPLOAD_ERROR;
import static com.xiaoshuidi.cloud.module.contract.enums.ErrorCodeConstants.NUMBER_FORMAT_ERROR;

/**
 * 房源签约合同信息同步
 */

@Component
@Slf4j
@RequiredArgsConstructor
public class ContractFillingsJob {

    private final ContractRoomService contractRoomService;
    private final FilingsApi<ContractSigningResp, ContractSigningBo> filingsApi;
    private final RoomHouseApi roomHouseApi;
    private final ContractRoommateService contractRoommateService;
    private final FilingsProperties filingsProperties;
    private final ContractFilingsService contractFilingsService;
    private final ContractFilingsLogService contractFilingsLogService;
    private final ElectronicContractMapper electronicContractMapper;


    @XxlJob("contractFillingsJob")
    @TenantIgnore
    public void execute() {
        Integer month = 1;
        try {
            String jobParam = XxlJobHelper.getJobParam();
            if(jobParam!=null){
                month= Integer.valueOf(jobParam);
            }

        } catch (Exception e) {
            throw new ServiceException(NUMBER_FORMAT_ERROR);
        }
        //查询最近一月内修改的合同 已生效，待入住，结束
        //备案过了 再次备案会提示已经备案过
        LocalDateTime minusMonths = LocalDateTime.now().minusMonths(month);
        List<ContractRoomDO> contractRoomDOS = contractRoomService.selectListByTimeAndStatus(minusMonths, Arrays.asList( ContractStatusEnum.CHECK_IN.getCode(), ContractStatusEnum.ABNORMAL_END.getCode(), ContractStatusEnum.NORMAL_END.getCode()));
        if (CollectionUtils.isEmpty(contractRoomDOS)) {
            return;
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        //查询已经备案成功的合同
        for (ContractRoomDO contract : contractRoomDOS) {
            //查询房源备案信息，如果没查到房源备案信息，则下次再进行备案
            ContractSigningBo bo = new ContractSigningBo();
            ContractFilingsDO filingsDO = new ContractFilingsDO();
            filingsDO.setContractId(contract.getId());
            filingsDO.setContractStatus(contract.getContractStatus());
            String contractPDF = contract.getContractUrl();
            if ("paper".equals(contract.getContractSort()) && contract.getContractUrl() == null) {
                log.error("=====纸质合同无合同附件信息，无法备案:contractId:{}", contract.getId());
                continue;
            }
            if ("electronic".equals(contract.getContractSort())) {
                LambdaQueryWrapper<ElectronicContractDO> electronicContractQueryWrapper = new LambdaQueryWrapper<>();
                electronicContractQueryWrapper.eq(ElectronicContractDO::getRoomContractId, contract.getId());
                ElectronicContractDO electronicContractDO = electronicContractMapper.selectOne(electronicContractQueryWrapper);
                if (electronicContractDO == null) {
                    log.error("=====电子合同无合同附件信息，无法备案:contractId:{}", contract.getId());
                    continue;
                }
                contractPDF = electronicContractDO.getDownloadUrl();
            }
            if(StringUtils.isEmpty(contractPDF)){
                log.error("没有合同附件地址，无法备案, 合同id:{}",contract.getId());
                continue;
            }
            //获取房源备案信息
            RoomHouseFilingsResp filingsResp = getRoomHouseFilingsResp(formatter, contract, bo);
            if (filingsResp == null) {
                log.error("=====无备案的房源信息:roomId:{}", contract.getRoomId());
                continue;
            }
            //从房管局获取文件上传url
            List<ContractFilingsDO> contractFilingsDOS = contractFilingsService.selectByContractId(contract.getId());
            contractFilingsDOS = null;
            if(CollectionUtils.isNotEmpty(contractFilingsDOS)){
                ContractFilingsDO contractFilingsDO = contractFilingsDOS.stream().filter(e -> e.getFilePath() != null).findFirst().orElse(null);
                //成功备案过，不需要在上传合同pdf文件
                if(contractFilingsDO!=null){
                    bo.setContractPDF(contractFilingsDO.getFilePath());
                    filingsDO.setFileSqeId(contractFilingsDO.getFileSqeId());
                    filingsDO.setFilePath(contractFilingsDO.getFilePath());
                }
            }else {
                try {
                    FilesUploadResp uploadResp = getContractPDF(contractPDF, contract.getContractNo());
                    bo.setContractPDF(uploadResp.getFilePath());
                    filingsDO.setFileSqeId(uploadResp.getFileSqeId());
                    filingsDO.setFilePath(uploadResp.getFilePath());
                } catch (Exception e) {
                    log.error("文件上传异常!! msg:{}",e.getMessage());
                    continue;
                }
            }

            //添加请求记录
            ContractFilingsLogDO filingsLogDO = new ContractFilingsLogDO();
            filingsLogDO.setContractId(contract.getId());
            filingsLogDO.setUrl(UriEnum.CONTRACT_SIGNING_URI.getUri());
            filingsDO.setContractNo(contract.getContractNo());
            filingsDO.setExternalRoomId(filingsResp.getExternalHouseId());
            filingsDO.setStatus(ContractFilingsEnum.UNFILINGS.getCode());
            try {
                CommonFilingsResponse<ContractSigningResp> response = filingsApi.execute(bo, UriEnum.CONTRACT_SIGNING_URI, ContractSigningResp.class);
                if (!response.getStatus()) {
                    log.error("获取合同备案信息错误: {}", response.getMsg());
                    throw new ServiceException(ErrorCodeConstants.CONTRACT_FILINGS_ERROR.getCode(), ErrorCodeConstants.CONTRACT_FILINGS_ERROR.getMsg() + response.getMsg());
                }
                String contractNo = response.getData().getContractNo();
                filingsDO.setExternalContractNo(contractNo);
                filingsDO.setSignStatus("1");
                String req = JSONObject.toJSONString(bo);
                filingsLogDO.setSendJson(req);
                filingsLogDO.setStatus(ContractFilingsLogEnum.SUCCESS.getCode());
                filingsLogDO.setReceiveJson(JSONObject.toJSONString(response));
            } catch (Exception e) {
                //出现异常时，记录到备案log  备案失败
                filingsDO.setSignStatus("0");
                filingsLogDO.setStatus(ContractFilingsLogEnum.FAILED.getCode());
                filingsLogDO.setErrMsg(e.getMessage());
            }
            contractFilingsService.insert(filingsDO);
            contractFilingsLogService.insert(filingsLogDO);
        }
    }
    private FilesUploadResp getContractPDF(String contractFile, String contractNo) {
        try {
            log.info("合同文件地址：{}", contractFile);
            String fileName = contractNo+".pdf";
            HttpRequest httpRequest = HttpRequest.get(contractFile);
            InputStream inputStream = httpRequest.execute().bodyStream();

            MultipartFile multipartFile = new MockMultipartFile(fileName,
                    fileName, MediaType.APPLICATION_PDF_VALUE,
                    org.apache.commons.compress.utils.IOUtils.toByteArray(inputStream));
            double fileSize = (double) (multipartFile.getSize()) / 1048576;
            if (fileSize > 2) {
                List<Image> testPdf = PdfToImgUtil.pdf3png(multipartFile.getInputStream(), 110);
                ByteArrayOutputStream outputStream = ImgToPdfUtil.Pdf(testPdf);
                multipartFile = new MockMultipartFile("file.pdf",
                        "file.pdf", MediaType.APPLICATION_PDF_VALUE,
                        outputStream.toByteArray());
            }
            fileSize = (double) (multipartFile.getSize()) / 1048576;
            //压缩后大于2M的话提示
            if (fileSize > 2) {
                log.error("文件大小超过2M，不支持上传!!! contractNo:{}",contractNo);
                throw new ServiceException(CONTRACT_FILE_UPLOAD_ERROR);
            }
            File file = new File(fileName);
            asFile( multipartFile.getInputStream(),file);
            String url =filingsProperties.getHost() + UriEnum.FILE_UPLOAD_URI.getUri();
            String result = restPostFilesUpload(url, contractNo, contractNo, file);
            String data = JSONObject.parseObject(result).getString("data");
            return  JSONObject.parseObject(data,FilesUploadResp.class);
        } catch (IOException e) {
            throw new ServiceException(ErrorCodeConstants.FILE_UPLOAD_ERROR.getCode(), ErrorCodeConstants.FILE_UPLOAD_ERROR.getMsg());
        }

    }

    @Nullable
    private RoomHouseFilingsResp getRoomHouseFilingsResp(DateTimeFormatter formatter, ContractRoomDO contract, ContractSigningBo bo) {
        CommonResult<RoomHouseFilingsResp> filings = roomHouseApi.getFilingsByRoomId(contract.getRoomId());
        RoomHouseFilingsResp filingsResp = filings.getData();
        if (!filings.isSuccess() || filingsResp == null || filingsResp.getExternalHouseId() == null) {
            log.error("===获取房源备案信息失败 roomID:{},response:{}", contract.getRoomId(), JSONObject.toJSONString(filingsResp));
            return null;
        }
        //组装备案信息

        bo.setUniqueContractId(contract.getId());
        bo.setHouseId(filingsResp.getExternalHouseId());
        bo.setLeaseMode(filingsResp.getIsWhole() ? 1 : 2);
        bo.setRoomId(contract.getRoomId());
        bo.setHouseArea(filingsResp.getSpace());
        /**
         *  出租人信息      需要找业务方获取
         */
        bo.setLessorName(filingsResp.getOwnerName());
        bo.setLessorCardType(1);
        bo.setLessorCardNo(filingsResp.getOwnerCardNo());
        bo.setLessorMobile(filingsResp.getOwnerPhone());
//        bo.setLessorAddress();
        bo.setLesseeName(contract.getCustomerName());
        bo.setLesseeCardType("1".equals(contract.getCustomerIdType()) ? CodeTypeEnum.ID.getCode() : CodeTypeEnum.OTHER.getCode());
        bo.setLesseeCardNo(contract.getCustomerIdNumber());
        bo.setLesseeMobile(contract.getCustomerPhone());
        bo.setLessorAddress(contract.getRenterAddress());
        //查询同住人信息
        List<ContractRoommateDO> roommateDOS = contractRoommateService.getListByContractId(contract.getId());
        if (CollectionUtils.isNotEmpty(roommateDOS)) {
            List<ContractSigningBo.Cotenant> cotenants = new ArrayList<>();
            for (ContractRoommateDO roommateDO : roommateDOS) {
                ContractSigningBo.Cotenant cotenant = new ContractSigningBo.Cotenant();
                cotenant.setName(roommateDO.getRoommateName());
                cotenant.setCardType("1".equals(roommateDO.getRoommateIdType()) ? CodeTypeEnum.ID.getCode() : CodeTypeEnum.OTHER.getCode());
                cotenant.setCardNO(roommateDO.getRoommateIdNumber());
                cotenant.setMobile(roommateDO.getRoommatePhone());
                cotenants.add(cotenant);
            }
        }
        bo.setLeaseDateStart(contract.getStartTime().format(formatter));
        bo.setLeaseDateEnd(contract.getEndTime().format(formatter));
        bo.setHouseDeliverDate(contract.getSignedTime().format(formatter));
        bo.setReletAdvanceDay(contract.getAdvancedDays());
        bo.setRentAmount(contract.getTotalRent().doubleValue());
        bo.setForegiftAmount(contract.getDeposit().doubleValue());
        bo.setRentPayCycle(converPayCycle(contract.getPayMethodF(), contract.getPayMethodY()));
        //租金不包含其他费项
        bo.setCostBearLessee("12");
        //承租人违约占比
//            bo.setLesseePenalty();
        //出租人违约占比
//            bo.setLessorPenalty();
        //合同双方持有合同份数
        bo.setContractNumOnePart("1");
        //合同签订电子文件 pdf
//            bo.setContractPDF();
        //合同状态
        bo.setStatusCode(convertStatus(contract.getContractStatus()));
        bo.setSecretKey(filingsProperties.getSecretKey());
        bo.setHouseUse("居住");
        bo.setMonthlyRent(contract.getMonthRent().intValue());
        return filingsResp;
    }

    private int convertStatus(String status) {
        if (ContractStatusEnum.ACTIVE.getCode().equals(status) || ContractStatusEnum.CHECK_IN.getCode().equals(status)) {
            return 1;
        } else if (ContractStatusEnum.NORMAL_END.getCode().equals(status)) {
            return 5;
        } else if (ContractStatusEnum.ABNORMAL_END.getCode().equals(status)) {
            return 3;
        }
        return 2;
    }




    private int converPayCycle(int methodF, int methodY) {
        if (methodY == 1 && methodF == 1) {
            return PaymentCycleEnum.ONE_ONE.getCode();
        } else if (methodY == 1 && methodF == 3) {
            return PaymentCycleEnum.ONE_THREE.getCode();
        } else if (methodY == 2 && methodF == 3) {
            return PaymentCycleEnum.TWO_THREE.getCode();
        } else if (methodY == 3 && methodF == 3) {
            return PaymentCycleEnum.THREE_THREE.getCode();
        } else if (methodY == 1 && methodF == 6) {
            return PaymentCycleEnum.ONE_SIX.getCode();
        } else if (methodY == 2 && methodF == 6) {
            return PaymentCycleEnum.TWO_SIX.getCode();
        } else if (methodY == 3 && methodF == 6) {
            return PaymentCycleEnum.THREE_SIX.getCode();
        } else if (methodY == 1 && methodF == 12) {
            return PaymentCycleEnum.ONE_ONE_YEAR.getCode();
        } else if (methodY == 2 && methodF == 12) {
            return PaymentCycleEnum.TWO_ONE_YEAR.getCode();
        } else if (methodY == 3 && methodF == 12) {
            return PaymentCycleEnum.THREE_ONE_YEAR.getCode();
        } else if (methodY == 1 && methodF == 2) {
            return PaymentCycleEnum.ONE_TWO.getCode();
        } else if (methodY == 2 && methodF == 2) {
            return PaymentCycleEnum.TWO_TWO.getCode();
        } else if (methodY == 3 && methodF == 2) {
            return PaymentCycleEnum.THREE_TWO.getCode();
        } else {
            return 14;
        }
    }


    /**
     * post 请求 文件上传
     * @param
     */
    public String restPostFilesUpload(String url, String fileName, String fileDataId, File file){
        try {
            String appKey = RSAUtil.encryptPublicKeyRSA(this.filingsProperties.getApiKey(), this.filingsProperties.getPublicKey());
            long timestamp = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
            OkHttpClient client = new OkHttpClient().newBuilder().build();
            RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
                    .addFormDataPart("SecretKey",filingsProperties.getSecretKey())
                    .addFormDataPart("FileName",fileName)
                    .addFormDataPart("FileDataId",fileDataId)
                    .addFormDataPart("files",file.getName(),
                            RequestBody.create(okhttp3.MediaType.parse("application/octet-stream"),
                                    file))
                    .build();
            Request request = new Request.Builder()
                    .url(url)
                    .method("POST", body)
                    .addHeader("appKey", appKey)
                    .addHeader("timestamp", String.valueOf(timestamp))
                    .addHeader("sign", "1")
                    .build();
            Response response = client.newCall(request).execute();
            String result = response.body().string();
            log.info("====文件上传返回result:{}",result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public  void asFile(InputStream inputStream,File file) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            inputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
